package com.cardone.common.web.support;

import com.cardone.common.util.MapperUtils;
import com.cardone.common.util.WebUtils;
import com.cardone.validator.Validator;
import com.cardone.validator.ValidatorRuleConfig;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * Created by Administrator on 2014/10/29.
 */
@lombok.extern.slf4j.Slf4j
public class InterfaceMethodDefaultSupport implements InterfaceMethodSupport {
    @lombok.Setter
    private java.util.Map<String, java.util.List<InterfaceMethod>> interfaceMethodMap;

    @Override
    public Object execution(javax.servlet.http.HttpServletRequest request) {
        if (org.apache.commons.collections.MapUtils.isEmpty(interfaceMethodMap)) {
            return null;
        }

        String interfaceMethodKey = StringUtils.defaultIfBlank(request.getMethod(), RequestMethod.GET.name());

        interfaceMethodKey = StringUtils.lowerCase(interfaceMethodKey);

        if (!interfaceMethodMap.containsKey(interfaceMethodKey)) {
            return null;
        }

        java.util.List<InterfaceMethod> InterfaceMethodList = interfaceMethodMap.get(interfaceMethodKey);

        if (CollectionUtils.isEmpty(InterfaceMethodList)) {
            return null;
        }

        return executionInterfaceMethodList(request, InterfaceMethodList);
    }

    private Object executionInterfaceMethodList(javax.servlet.http.HttpServletRequest request, java.util.List<InterfaceMethod> interfaceMethodList) {
        java.util.Map<String, Object> parameterMap = org.springframework.web.util.WebUtils.getParametersStartingWith(request, null);

        String json = null;

        Validator validator = com.cardone.context.ContextHolder.getBean(Validator.class);

        for (InterfaceMethod interfaceMethod : interfaceMethodList) {
            if (CollectionUtils.isEmpty(interfaceMethod.getParameterList())) {
                continue;
            }

            for (ValidatorRuleConfig validatorRuleConfig : interfaceMethod.getParameterList()) {
                if (StringUtils.isBlank(validatorRuleConfig.getName()) || StringUtils.startsWith(validatorRuleConfig.getName(), com.cardone.common.Characters.meter.stringValue())) {
                    if (StringUtils.isBlank(json)) {
                        json = WebUtils.getJsonString(request);
                    }

                    validator.validateThrowException(json, validatorRuleConfig);
                } else if (StringUtils.startsWith(validatorRuleConfig.getName(), "#")) {
                    validator.validateThrowException(parameterMap, validatorRuleConfig);
                } else {
                    validator.validateThrowException(parameterMap.get(validatorRuleConfig.getName()), validatorRuleConfig);
                }
            }
        }

        if (interfaceMethodList.size() == 1) {
            InterfaceMethod interfaceMethod = interfaceMethodList.get(0);

            Object data = executionInterfaceMethod(request, interfaceMethod, parameterMap, json);

            if (org.apache.commons.lang3.StringUtils.isBlank(interfaceMethod.getKey())) {
                return data;
            }

            java.util.Map<String, Object> dataMap = Maps.newLinkedHashMap();

            dataMap.put(interfaceMethod.getKey(), data);

            return dataMap;
        }

        java.util.Map<String, Object> dataMap = Maps.newLinkedHashMap();

        for (InterfaceMethod interfaceMethod : interfaceMethodList) {
            Object data = executionInterfaceMethod(request, interfaceMethod, parameterMap, json);

            if (org.apache.commons.lang3.StringUtils.isBlank(interfaceMethod.getKey())) {
                continue;
            }

            dataMap.put(interfaceMethod.getKey(), data);
        }

        return dataMap;
    }

    private Object executionInterfaceMethod(HttpServletRequest request, InterfaceMethod interfaceMethod, Map<String, Object> parameterMap, String json) {
        if (interfaceMethod.getValue() != null) {
            return interfaceMethod.getValue();
        }

        if (interfaceMethod.getInterfaceBean() == null) {
            return null;
        }

        if (org.apache.commons.lang3.StringUtils.isBlank(interfaceMethod.getMethodName())) {
            return null;
        }

        if (CollectionUtils.isNotEmpty(interfaceMethod.getParameterList())) {
            return executionInterfaceMethodParameterNames(request, interfaceMethod, parameterMap, json);
        }

        return executionInterfaceMethodParameterValues(interfaceMethod, null);
    }

    private Object executionInterfaceMethodParameterNames(javax.servlet.http.HttpServletRequest request, com.cardone.common.web.support.InterfaceMethod interfaceMethod, java.util.Map<String, Object> parameterMap, String jsonString) {
        Object[] parameterValues = new Object[interfaceMethod.getParameterList().size()];

        for (int i = 0; i < parameterValues.length; i++) {
            ValidatorRuleConfig validatorRuleConfig = interfaceMethod.getParameterList().get(i);

            if (StringUtils.isBlank(validatorRuleConfig.getName()) && ((validatorRuleConfig.getValue() != null) || (validatorRuleConfig.getOverrideValue() != null))) {
                parameterValues[i] = org.apache.commons.lang3.ObjectUtils.defaultIfNull(validatorRuleConfig.getOverrideValue(), validatorRuleConfig.getValue());

                continue;
            }

            if (StringUtils.startsWith(validatorRuleConfig.getName(), "*-map") || "#".equals(validatorRuleConfig.getName())) {
                Map<String, Object> newParameterMap = Maps.newHashMap();

                if ((validatorRuleConfig.getValue() != null) && (validatorRuleConfig.getValue() instanceof Map)) {
                    newParameterMap.putAll((Map<String, Object>) validatorRuleConfig.getValue());
                }

                newParameterMap.putAll(parameterMap);

                if (StringUtils.startsWith(validatorRuleConfig.getName(), "*-map")) {
                    newParameterMap.putAll(MapperUtils.getMapForJson(jsonString));
                }

                if ((validatorRuleConfig.getOverrideValue() != null) && (validatorRuleConfig.getOverrideValue() instanceof Map)) {
                    newParameterMap.putAll((Map<String, Object>) validatorRuleConfig.getOverrideValue());
                }

                parameterValues[i] = newParameterMap;

                continue;
            }

            if (validatorRuleConfig.getOverrideValue() != null) {
                parameterValues[i] = validatorRuleConfig.getOverrideValue();

                continue;
            }

            if (StringUtils.isBlank(validatorRuleConfig.getName()) || com.cardone.common.Characters.meter.stringValue().equals(validatorRuleConfig.getName())) {
                parameterValues[i] = org.apache.commons.lang3.ObjectUtils.defaultIfNull(jsonString, validatorRuleConfig.getValue());

                continue;
            }

            parameterValues[i] = org.apache.commons.lang3.ObjectUtils.defaultIfNull(parameterMap.get(validatorRuleConfig.getName()), validatorRuleConfig.getValue());
        }

        return executionInterfaceMethodParameterValues(interfaceMethod, parameterValues);
    }

    private Object executionInterfaceMethodParameterValues(InterfaceMethod interfaceMethod, Object[] parameterValues) {
        try {
            Object data = org.apache.commons.lang3.reflect.MethodUtils.invokeMethod(interfaceMethod.getInterfaceBean(), interfaceMethod.getMethodName(), parameterValues);

            return returnDataMapId(data, interfaceMethod.getMapId());
        } catch (Exception e) {
            throw new com.cardone.context.DictionaryException(e.getMessage(), e);
        }
    }

    private Object returnDataMapId(Object data, String mapId) {
        if (data == null) {
            return null;
        }

        if (data instanceof String) {
            return data;
        }

        if (org.apache.commons.lang3.StringUtils.isBlank(mapId)) {
            return data;
        }

        return com.cardone.context.ContextHolder.getBean(org.dozer.Mapper.class).map(data, java.util.Map.class, mapId);
    }
}
